/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.parallelCompiler.annot;

import java.io.*;
import java.lang.reflect.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.HashMap;

/**
 *
 * @author Adnan
 */
public class DependencyFileGenerator {

    Class mClass;
    String filePath;
    private HashMap<String, String> typeMap;

    public DependencyFileGenerator(Class mClass, String path) {
        this.mClass = mClass;
        this.filePath = path;


    }

    public DependencyFileGenerator(Class mClass) {
        this.mClass = mClass;
        this.filePath = mClass.getName() + ".txt";


    }

    /**
     * Generate File
     *
     * @throws IOException
     */
    public void generate() throws IOException {


        createFieldTypeMap();
        File outputFile = new File(filePath);
        PrintWriter fw = new PrintWriter(outputFile);

        fw.println(generateComments());

        Method[] methods = mClass.getDeclaredMethods();

        for (Method method : methods) {
            DependencyAnnotation dependencyAnnotation = method.getAnnotation(DependencyAnnotation.class);
            if (dependencyAnnotation != null) {

                Class<?>[] parameterNames = method.getParameterTypes(); // will return null if not found
                String parms = encodeClassNameToClassFileFormat(parameterNames);
                Class<?> returnTypeC = method.getReturnType();
                String returnType = encodeClassNameToClassFileFormat(new Class<?>[]{returnTypeC});

                println(fw, dependencyAnnotation, mClass.getCanonicalName().replace(".", "/"), method.getName(), parms, returnType);
            }
        }
        fw.flush();
        fw.close();

    }

    /**
     * Write an entry to file
     *
     * @param fw
     * @param dependencyAnnotation
     * @param className
     * @param methodName
     * @param parms
     * @throws IOException
     */
    private void println(PrintWriter fw, DependencyAnnotation dependencyAnnotation, String className, String methodName, String parms, String returnType) throws IOException {

        String parents = "";
        for (int parent : dependencyAnnotation.parents()) {
            parents = parents + "," + parent;
        }
        fw.println(dependencyAnnotation.id() + "," + className + "," + methodName + "(" + parms + ")" + returnType + "" + parents + "");

    }

    /**
     * *
     * Create Field Map - Java to Java Class file format Map
     */
    private void createFieldTypeMap() {
//L<classname>;	 reference	 an instance of class <classname>
//[    Ljava/lang/
        typeMap = new HashMap<String, String>();
        typeMap.put("int", "I");
        typeMap.put("boolean", "Z");
        typeMap.put("short", "S");
        typeMap.put("float", "F");
        typeMap.put("long", "J");
        typeMap.put("double", "D");
        typeMap.put("char", "C");
        typeMap.put("byte", "B");
        typeMap.put("void", "V");


    }

    private String getArrayIdentifire(String className) {

        if (className == null) {
            return "";
        }
        String toReturn = "";
        for (int i = 0; i < className.length(); i++) {
            if (className.charAt(i) == '[') {
                toReturn += "[";
            }
        }
        return toReturn;
    }

    /**
     * *
     * This method convert a class name to JAVA class file name format
     *
     * @param classNames
     * @return
     */
    private String encodeClassNameToClassFileFormat(Class<?>[] classNames) {
        String parms = "";
        for (Class<?> class1 : classNames) {
            parms += getArrayIdentifire(class1.getName());
            String className = typeMap.get(class1.getName());
            parms += (className == null || className.equals("null")) ? "L" + class1.getCanonicalName().replace(".", "/").replace("[", "").replace("]", "") : className.replace("[", "").replace("]", ";");
        }
        return parms;
    }

    private String generateComments() {

        String comments = "# Java functional dependency information";
        comments += "\n# Generated date : " + getCurrentDate();
        comments += "\n# Generated by : " + System.getProperty("user.name");
        comments += "\n# Format : [id],[fully qualified class name],[function name (parms)return type],[parents/dependencies]\n";

        return comments;

    }

    private String getCurrentDate() {
        DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        Calendar cal = Calendar.getInstance();
        return dateFormat.format(cal.getTime());
    }
}
